use super::{Result, COMMON_CONFIG_NODE_PATH};
use etcd_manager_util::common::{NodeChangeType, NodeValueModel};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock};
use string_util::string_error::StringErrorBuilder;

lazy_static::lazy_static! {
  static ref COMMON_CONFIG:RwLock<Arc<CommonConfig>>={
        let result = CommonConfig::default();
        RwLock::new(Arc::new(result))
    };
}

crate::config_handler! {CommonConfig}

#[derive(Serialize, Deserialize)]
pub struct CommonConfig {
    /// 是否加载成功
    #[serde(skip)]
    pub is_error: bool,

    /// mongo 连接字符串
    #[serde(rename(serialize = "MongoConnection"))]
    pub mongo_connection: String,
    /// redis连接
    #[serde(rename(serialize = "RedisConnection"))]
    pub redis_connection: String,
}

impl CommonConfig {
    pub fn node_path() -> String {
        COMMON_CONFIG_NODE_PATH.to_string()
    }

    pub fn weight() -> u32 {
        1u32
    }

    #[allow(unused)]
    pub fn module_name() -> &'static str {
        "CommonConfig"
    }

    pub fn load(_change_type: NodeChangeType, val: &NodeValueModel) -> Result {
        let mut err = StringErrorBuilder::new("CommonConfig");

        // 加载
        let result: serde_json::Result<CommonConfig> = serde_json::from_str(val.value.as_str());
        let mut config_obj;
        match result {
            Ok(val) => config_obj = val,
            Err(inner_err) => {
                return err
                    .append(format!("Deserialize err:{:?}", inner_err).as_str())
                    .to_result()
            }
        }

        // check
        if config_obj.mongo_connection.is_empty() {
            err.append("mongo_connection need be set");
        }
        if config_obj.redis_connection.is_empty() {
            err.append("redis_connection need be set");
        }

        config_obj.is_error = err.is_error();
        if config_obj.is_error {
            return err.to_result();
        }

        {
            let mut writer = COMMON_CONFIG.write().unwrap();
            *writer = Arc::new(config_obj);
        }

        Ok(())
    }
}

impl Default for CommonConfig {
    fn default() -> Self {
        CommonConfig {
            mongo_connection: "".to_string(),
            redis_connection: "".to_string(),
            is_error: true,
        }
    }
}

#[allow(unused)]
pub fn get_common_config() -> Arc<CommonConfig> {
    let reader = COMMON_CONFIG.read().unwrap();
    reader.clone()
}
